package com.example.judge.service.judge.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.example.api.domain.JudgeResult;
import com.example.api.domain.JudgeSubmitDTO;
import com.example.core.constants.Constants;
import com.example.core.enums.CodeRunStatus;
import com.example.core.enums.ProgramType;
import com.example.core.utils.JsonUtils;
import com.example.judge.constants.JudgeConstants;
import com.example.judge.domain.judge.CaseJudgeResult;
import com.example.judge.domain.sandbox.QuestionCase;
import com.example.judge.domain.sandbox.SandBoxExecuteResult;
import com.example.judge.domain.user.UserSubmit;
import com.example.judge.mapper.UserSubmitMapper;
import com.example.judge.service.judge.IJudgeService;
import com.example.judge.service.sandbox.ISandBoxPoolService;
import com.example.scurity.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class JudgeServiceImpl extends ServiceImpl<UserSubmitMapper, UserSubmit> implements IJudgeService {
//    @Autowired
//    private ISandBoxService sandBoxService;

    @Autowired
    private ISandBoxPoolService sandBoxService;

    @Autowired
    private UserSubmitMapper userSubmitMapper;

    @Override
    @Async("judeThreadExecutor")
    public void doJudge(JudgeSubmitDTO dto) {
        log.info("thread-name：" + Thread.currentThread().getName());
        //整理输入输出用例
        List<QuestionCase> questionCaseList = JsonUtils.toList(dto.getQuestionCase(), QuestionCase.class);
        //输入
        List<String> inputList = questionCaseList.stream().map(QuestionCase::getInput).toList();
        //输出
        List<String> outputList = questionCaseList.stream().map(QuestionCase::getOutput).toList();
        //代码拼接
        String userCode = codeConnect(dto.getUserCode(), dto.getMainFunc());

        SandBoxExecuteResult executeResult = null;
        if (ProgramType.JAVA.getValue().equals(dto.getProgramType())) {
            //执行代码并获取结果
            executeResult = sandBoxService.executeJavaCode(dto.getUserId(), inputList, userCode);
        }
        //调用代码沙箱执行代码 失败直接判0分。得到执行结果，比对执行结果  全正确并且没有超过内存和时间限制计算得分
        JudgeResult judgeResult = new JudgeResult();
        UserSubmit userSubmit;
        if (executeResult != null && CodeRunStatus.SUCCEED.equals(executeResult.getRunStatus())) { //执行成功
            //对比实际输出结果和预期输出结果
            List<String> executeOutputList = executeResult.getOutputList();
            //检查时间限制和空间限制是否符合要求
            Long spaceLimit = dto.getSpaceLimit();
            Long timeLimit = dto.getTimeLimit();
            Long useTime = executeResult.getUseTime();
            Long useMemory = executeResult.getUseMemory();
            userSubmit = doJudge(dto, inputList, outputList, executeOutputList, judgeResult, spaceLimit, useMemory, timeLimit, useTime);
        } else {
            userSubmit = new UserSubmit();
            BeanUtils.copyProperties(dto, userSubmit);
            userSubmit.setPass(Constants.FALSE);
            userSubmit.setScore(JudgeConstants.ERROR_SCORE);
            if (executeResult != null) {
                userSubmit.setErrorMessage(executeResult.getErrorMsg());  //将错误信息返回
            }
        }
        UserSubmit lastSubmit = userSubmitMapper.selectOne(new LambdaQueryWrapper<UserSubmit>()
                .eq(UserSubmit::getUserId, userSubmit.getUserId())
                .eq(UserSubmit::getQuestionId, userSubmit.getQuestionId())
                .isNull(userSubmit.getExamId() == null, UserSubmit::getExamId)
                .eq(userSubmit.getExamId() != null, UserSubmit::getExamId, userSubmit.getExamId()));
        if (lastSubmit != null) {
            userSubmit.setSubmitId(lastSubmit.getSubmitId());
        }
        saveOrUpdate(userSubmit);
    }

    private String codeConnect(String userCode, String mainFunc) {
        String targetCharacter = "}";
        int targetLastIndex = userCode.lastIndexOf(targetCharacter);
        System.out.println(targetLastIndex);
        if (targetLastIndex != -1) {
            return userCode.substring(0, targetLastIndex) + "\n" + mainFunc + "\n" + userCode.substring(targetLastIndex);
        }
        throw new ServiceException("");
    }

    private static UserSubmit doJudge(JudgeSubmitDTO dto, List<String> inputList, List<String> expectOutputList,
                                      List<String> executeOutputList, JudgeResult judgeResult,
                                      Long spaceLimit, Long useMemory, Long timeLimit, Long useTime) {
        UserSubmit userSubmit = new UserSubmit();
        BeanUtils.copyProperties(dto, userSubmit);
        userSubmit.setPass(Constants.FALSE); //用户代码是否执行通过  默认设置为未通过
        if (expectOutputList.size() != executeOutputList.size()) {
            userSubmit.setScore(JudgeConstants.ERROR_SCORE);
            userSubmit.setErrorMessage(JudgeConstants.ERROR_ANSWER);
            return userSubmit;
        }
        boolean allPassed = true;
        int caseSize = inputList.size();
        int outPutSize = executeOutputList.size();
        List<CaseJudgeResult> caseJudgeResultList = new ArrayList<>();
        for (int i = 0; i < caseSize; i++) {
            CaseJudgeResult caseJudgeResult = new CaseJudgeResult();
            caseJudgeResult.setInput(inputList.get(i));
            String expectOutput = expectOutputList.get(i);
            caseJudgeResult.setExpectOutPut(expectOutput);
           if (i < outPutSize) {
               String output = executeOutputList.get(i);
               caseJudgeResult.setOutPut(output);
               if (!expectOutput.equals(output)) {
                   allPassed = false;
               }
           } else {
               allPassed = false;
           }
            caseJudgeResultList.add(caseJudgeResult);
        }
        userSubmit.setCaseJudgeRes(JSON.toJSONString(caseJudgeResultList));
        if (!allPassed) {
            userSubmit.setScore(JudgeConstants.ERROR_SCORE);
            userSubmit.setErrorMessage(JudgeConstants.ERROR_ANSWER);
            return userSubmit;
        }
//        for (int i = 0; i < outputList.size(); i++) {
//            String output = outputList.get(i);
//            String executeOutput = expectOutputList.get(i);
//            if (!executeOutput.equals(output)) {
//                userSubmit.setScore(JudgeConstants.ERROR_SCORE);
//                userSubmit.setErrorMessage(JudgeConstants.ERROR_ANSWER);
//                return userSubmit;
//            }
//        }
        if (spaceLimit != null && useMemory > spaceLimit) {
            userSubmit.setScore(JudgeConstants.ERROR_SCORE);
            userSubmit.setErrorMessage(JudgeConstants.OUT_OF_MEMORY);
            return userSubmit;
        }
        if (timeLimit != null && useTime > timeLimit) {
            userSubmit.setScore(JudgeConstants.ERROR_SCORE);
            userSubmit.setErrorMessage(JudgeConstants.OUT_OF_TIME);
            return userSubmit;
        }
        //完全符合预期
        //得分 = 基础分 * 难度系数
        int score = JudgeConstants.DEFAULT_SCORE * dto.getDifficulty();
        userSubmit.setScore(score);
        userSubmit.setPass(Constants.TRUE);
        return userSubmit;
    }
}
